#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <semaphore.h>

template<typename T>
class RingQueue
{
public:
    RingQueue(int cap) : _ringQueue(cap), _cap(cap), _productor_index(0), _consumer_index(0)
    {
        sem_init(&_blank_sem, 0, _cap);
        sem_init(&_data_sem, 0, 0);

        pthread_mutex_init(&_productor_mutex, nullptr);
        pthread_mutex_init(&_consumer_mutex, nullptr);
    }

    // 生产者生产数据
    void Push(const T& in)
    {
        // 申请空间资源
        P(_blank_sem);

        // 加锁
        Lock(_productor_mutex);
        // 成功申请后，向队列中入数据
        _ringQueue[_productor_index++] = in;
        _productor_index %= _cap;
        Unlock(_productor_mutex);
        // 释放数据资源
        V(_data_sem);
    }

    void Pop(T* data)
    {
        // 申请数据资源
        P(_data_sem);

        // 加锁
        Lock(_consumer_mutex);
        // 成功申请后，向队列中入数据
        *data = _ringQueue[_consumer_index++];
        _consumer_index %= _cap;
        Unlock(_consumer_mutex);
        // 释放空间资源
        V(_blank_sem);
    }

    ~RingQueue()
    {
        sem_destroy(&_blank_sem);
        sem_destroy(&_data_sem);

        pthread_mutex_destroy(&_productor_mutex);
        pthread_mutex_destroy(&_consumer_mutex);
    }
private:
    void P(sem_t& sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t& sem)
    {
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }

    void Unlock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

    // 1. 环形队列
    std::vector<T> _ringQueue;
    int _cap;
    // 2. 生产者、消费者下标
    int _productor_index;
    int _consumer_index;
    // 3. 定义信号量
    sem_t _blank_sem; // 空间资源
    sem_t _data_sem; // 数据资源
    // 4. 定义互斥锁
    pthread_mutex_t _productor_mutex;
    pthread_mutex_t _consumer_mutex;
};